class_name Ball
extends AnimatableBody2D

enum State {CARRIED, FREEDOM, SHOOT}
#弹跳系数
const BOUNCINESS :=0.8
#传球阈值，超过则高传
const DISTANCE_HIGH_PASS := 130
const KICKOFF_PASS_DISTANCE := 30.0
const DURACTION_TUMBLE_LOCK := 200
const DURACTION_PASS_LOCK := 500

const TUMBLE_HEIGHT_VELOCITY:= 3.0

#@export var air_contect_min_height : float
#@export var air_contect_max_height : float

@export var friction_air : float
@export var friction_ground : float

@onready var animation_player: AnimationPlayer = %AnimationPlayer
@onready var player_dection_area: Area2D = %PlayerDectionArea
@onready var ball_sprite: Sprite2D = $BallSprite
@onready var scoring_ray_cast: RayCast2D = %ScoringRayCast
@onready var shoot_particles: GPUParticles2D = %ShootParticles
@onready var player_proximity_area: Area2D = %PlayerProximityArea

var carrier: Player = null
var current_state :BallState = null
var height := 0.0
var height_velocity := 0.0
var spawn_position := Vector2.ZERO
var state_factory = BallStateFactory.new()
var velocity := Vector2.ZERO

func _ready() -> void:
	switch_state(State.FREEDOM)
	spawn_position = position
	GameEvents.team_reset.connect(on_team_reset.bind())
	GameEvents.kickoff_started.connect(on_kickoff_started.bind())

func _process(delta: float) -> void:
	ball_sprite.position = Vector2.UP * height
	scoring_ray_cast.rotation = velocity.angle()  

func switch_state(state: Ball.State,data:BallStateData = BallStateData.new()) -> void:
	if current_state != null:
		current_state.queue_free()
	current_state = state_factory.get_fresh_state(state);
	current_state.setup(self,data,animation_player,player_dection_area,carrier,ball_sprite,shoot_particles)
	current_state.state_transition_requested.connect(switch_state.bind())
	current_state.name = "BallStateMachine" + str(state)
	
	call_deferred("add_child",current_state)

func shoot(shot_velocity:Vector2) -> void:
	velocity = shot_velocity
	carrier = null
	switch_state(Ball.State.SHOOT)

func tumble(tumble_velocity:Vector2) -> void:
	velocity = tumble_velocity
	carrier = null
	height_velocity = TUMBLE_HEIGHT_VELOCITY
	
	switch_state(Ball.State.FREEDOM,BallStateData.build().set_lock_duraction(DURACTION_TUMBLE_LOCK))

# 向目标传球
func pass_to(destination:Vector2,lock_duraction : int = DURACTION_PASS_LOCK) ->void:
	var direction := position.direction_to(destination)
	var distance := position.distance_to(destination)
	var instensity := sqrt(2 * distance *  friction_ground)
	
	velocity = instensity * direction
	if distance > DISTANCE_HIGH_PASS:
		height_velocity = BallState.GRAVITY * distance / (1.8 * instensity)
	carrier = null
	
	switch_state(Ball.State.FREEDOM,BallStateData.build().set_lock_duraction(lock_duraction))
	
func stop() -> void:
	velocity = Vector2.ZERO

func can_air_interact() -> bool :
	return current_state != null and current_state.can_air_interact()

func can_air_connect(air_contect_min_height : float,air_contect_max_height : float) -> bool:
	return height >= air_contect_min_height and height < air_contect_max_height

func is_heading_for_scoring_area(scoring_area:Area2D) -> bool:
	if not scoring_ray_cast.is_colliding():
		return false
	return scoring_ray_cast.get_collider() == scoring_area

func get_proximity_teammates_count(country: String) -> int:
	var players := player_proximity_area.get_overlapping_bodies()
	return players.filter(func(p: Player): return p.country == country).size()

func on_team_reset():
	position = spawn_position
	velocity = Vector2.ZERO
	switch_state(State.FREEDOM)

func on_kickoff_started():
	pass_to(spawn_position + Vector2.DOWN * KICKOFF_PASS_DISTANCE, 0)
